package com.sf.proxy.chain;

import com.sf.proxy.chain.handler.Handler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

@Service("proxyUrlChain")
@Slf4j
public class ProxyUrlCollectorChain implements Chain, ApplicationContextAware {

    private static ProxyUrlCollectorChain instance;

    private List<Handler> handlers;

    private ApplicationContext applicationContext;

    @PostConstruct
    public synchronized void init(){
        log.info("the chain is starting to collect the handler ...");
        handlers = new LinkedList<>();
        handlers.add((Handler)applicationContext.getBean("blackNameUrlHandler"));
        handlers.add((Handler)applicationContext.getBean("finalUrlHandler"));

        //can not modify the handler after init
        Collections.unmodifiableList(handlers);

        instance = this;
    }

    @Override
    public void execute(ChainContext context) {
        for (Handler handler:handlers){
            try{
                handler.handle(context);
            }catch (Exception e){
                if (handler.stop()){
                    log.warn("need to stop the chain execution, because because the handler need to stop "+getStackTrace(e));
                    return;
                }
            }
        }
    }

    public static Chain getInstance(){
        return instance;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private static String getStackTrace(Throwable t)
    {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        try
        {
            t.printStackTrace(pw);
            return sw.toString();
        }
        finally
        {
            pw.close();
        }
    }


}
